/***************************************************************************************************
 *Copyright(C),2010-2016,Sumscope
 *FileName	:  BaseString.cpp
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2016/01/12
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#include "BaseString.h"

#ifndef BASSERT
#define BASSERT  //
#endif

namespace qb {
namespace base {

static char inline GetCaseChar(bool igoreCase, const char& c) {
  return (!igoreCase && (c >= 'A' && c <= 'Z')) ? c + 32 : c;
}

BaseString::BaseString() : m_string(0), m_size(0), m_capcity(INIT_CAPCITY) {
  reset();
}
BaseString::BaseString(int capcity)
    : m_string(0), m_size(0), m_capcity(capcity <= 1 ? 1 : capcity) {
  reset();
  expand(m_capcity);
}

BaseString::BaseString(const Element* str)
    : m_string(0), m_size(0), m_capcity(INIT_CAPCITY) {
  reset();
  append(str);
}

BaseString::BaseString(const Element* str, int len)
    : m_string(0), m_size(0), m_capcity(INIT_CAPCITY) {
  reset();
  append(str, len);
}

BaseString::BaseString(const BaseString& bs)
    : m_string(0), m_size(0), m_capcity(INIT_CAPCITY) {
  reset();
  append(bs);
}

BaseString::~BaseString() { reset(); }

BaseString::BaseString(BaseString&& bs)
    : m_string(0), m_size(0), m_capcity(INIT_CAPCITY) {
  m_null[0] = m_null[1] = 0;
  std::swap(m_string, bs.m_string);
  std::swap(m_size, bs.m_size);
  std::swap(m_capcity, bs.m_capcity);
}
BaseString& BaseString::operator=(BaseString&& bs) {
  if (this != &bs) {
    reset();
    std::swap(m_string, bs.m_string);
    std::swap(m_size, bs.m_size);
    std::swap(m_capcity, bs.m_capcity);
  }
  return *this;
}
void BaseString::expand(int size) {
  // 额外增加的1个字节使得用于字符串0强行结尾
  if (m_string && size <= m_capcity) return;
  int capcity = m_capcity + m_capcity / 2;
  capcity = capcity < INIT_CAPCITY ? INIT_CAPCITY : capcity;
  capcity = capcity < size ? size : capcity;
  capcity = (capcity / 4 + 1) * 4 - 1;
  int bytes = sizeof(Element) * (capcity + 1);
  Element* arr = new (std::nothrow) Element[capcity + 1];
  BASSERT(arr);
  memset(arr, 0, bytes);
  if (m_size > 0) {
    BASSERT(m_string && m_size < capcity);
    memcpy(arr, m_string, m_size * sizeof(Element));
  }
  if (m_string) delete[] m_string;
  m_string = arr;
  m_capcity = capcity;
}

BaseString::ThisType& BaseString::operator=(Element c) { return assign(c); }

BaseString::ThisType& BaseString::operator=(const BaseString& bs) {
  return assign(bs);
}

BaseString::ThisType& BaseString::operator=(const Element* str) {
  return assign(str);
}

void BaseString::clear() {
  m_size = 0;
  Element e = {0};
  if (m_string) m_string[0] = 0;
}

void BaseString::reset() {
  if (m_string) delete[] m_string;
  m_string = 0;
  m_size = 0;
  m_capcity = INIT_CAPCITY;
  m_null[0] = 0;
  m_null[1] = 0;
}

BaseString::ThisType& BaseString::assign(Element c) { return assign(&c, 1); }

BaseString::ThisType& BaseString::assign(const Element* str) {
  return assign(str, str ? length(str) : 0);
}

BaseString::ThisType& BaseString::assign(const Element* str, int len) {
  clear();
  return append(str, len);
}

BaseString::ThisType& BaseString::assign(const BaseString::ThisType& br) {
  clear();
  append(br.m_string, br.m_size);
  return *this;
}

BaseString::ThisType& BaseString::append(int count, Element c) {
  if (count > 0) {
    expand(size() + count);
    for (int i = 0; i < count; i++) {
      append(c);
    }
  }
  return *this;
}
BaseString::ThisType& BaseString::append(Element c) { return append(&c, 1); }

BaseString::ThisType& BaseString::append(const Element* str) {
  return append(str, str ? length(str) : 0);
}

BaseString::ThisType& BaseString::append(const Element* str, int len) {
  if (str && len > 0) {
    if ((str >= m_string && str <= m_string + m_size) ||
        (m_string >= str && m_string <= str + len)) {
      char* buf = new (std::nothrow) char[m_size + len + 1];
      if (buf) {
        if (m_string && m_size > 0) memcpy(buf, m_string, m_size);
        memcpy(buf + m_size, str, len);
        buf[m_size + len] = '\0';
        if (m_string) delete[] m_string;
        m_size = m_size + len;
        m_capcity = m_size + len;
        m_string = buf;
      }
      return *this;
    }
    if (!m_string || m_size + len > m_capcity) expand(m_size + len);
    if (m_string && m_size + len <= m_capcity) {
      memcpy(m_string + m_size, str, sizeof(Element) * len);
      m_size += len;
      m_string[m_size] = 0;
    }
  }
  return *this;
}

BaseString::ThisType& BaseString::append(const BaseString::ThisType& br) {
  return append(br.m_string, br.m_size);
}

BaseString::ThisType& BaseString::push_back(Element c) { return append(c); }

BaseString::ThisType& BaseString::push_back(const Element* str) {
  return append(str);
}

BaseString::ThisType& BaseString::push_back(const Element* str, int len) {
  return append(str, len);
}

BaseString::ThisType& BaseString::push_back(const BaseString::ThisType& br) {
  return append(br);
}

BaseString::ThisType& BaseString::insert(int pos, const Element* str, int len) {
  if (str && len > 0) {
    pos = (pos < 0 || pos >= m_size) ? m_size : pos;
    if (!m_string || m_size <= 0) {
      append(str, len);
    } else if (m_size + len <= m_capcity) {
      for (int i = m_size + len - 1; i >= pos + len; i--) {
        m_string[i] = m_string[i - len];
      }
      for (int i = 0; i < len; i++) {
        m_string[i + pos] = str[i];
      }
      m_size += len;
    } else {
      ThisType temp;
      temp.expand(m_size + len);
      temp.append(m_string, pos);
      temp.append(str, len);
      temp.append(m_string, m_size - pos);
      swap(temp);
    }
  }
  return *this;
}

BaseString::ThisType& BaseString::erase(int pos, int len /*=1*/) {
  if (m_string && m_size > 0 && pos >= 0 && pos < m_size && len > 0) {
    for (int i = pos; i < m_size; i++) {
      m_string[i] = (i + len >= m_size) ? 0 : m_string[i + len];
    }
  }
  return *this;
}

BaseString::ThisType& BaseString::replace(int pos, int len, const Element* str,
                                          int size) {
  if (str && size > 0 && pos >= 0 && len >= 0 && pos + len <= m_size) {
    ThisType temp;
    temp.expand(m_size - len + size);
    temp.append(m_string, pos);
    temp.append(str, size);
    temp.append(m_string + pos + len, m_size - pos - len);
    swap(temp);
  }
  return *this;
}

int BaseString::find(Element c, int offset) const {
  if (m_string && m_size > 0) {
    for (int i = offset; i < m_size; i++) {
      if (m_string[i] == c) return i;
    }
  }
  return npos;
}

int BaseString::find(const Element* str, int offset) const {
  if (!m_string || m_size <= 0) return npos;
  if (offset < 0 || offset >= m_size) return npos;
  int len = str ? length(str) : 0;
  if (len <= 0) return npos;
  if (len + offset > m_size) return npos;
  int pos = SearchString(m_string + offset, m_size - offset, str, len, false);
  pos = pos >= 0 ? (pos + offset) : pos;
  return pos;
}

int BaseString::rfind(Element c, int offset) const {
  if (m_string && m_size > 0) {
    for (int i = m_size - 1; i >= 0; i--) {
      if (m_string[i] == c) return i;
    }
  }
  return npos;
}

void BaseString::substr(int offset, int len, BaseString::ThisType& bs) const {
  bs.clear();
  if (m_string && m_size > 0 && len > 0) {
    int pos = offset < 0 ? 0 : offset;
    int size = (pos + len) > m_size ? (m_size - pos) : len;
    bs.append(m_string + pos, size);
  }
}

BaseString::ThisType BaseString::substr(int offset, int len) const {
  ThisType bs;
  substr(offset, len, bs);
  return bs;
}

int BaseString::compare(const Element* str, int len) const {
  if (!str || len <= 0) return size() <= 0 ? 0 : 1;  // 有值为大
  if (size() <= 0) return (!str || len <= 0) ? 0 : -1;

  // 字典排序
  int cmp = len < size() ? len : size();
  int ret = memcmp(m_string, str, cmp);
  if (ret == 0) return len == size() ? 0 : (cmp == len ? 1 : -1);
  return ret;
}

void BaseString::swap(BaseString& bs) {
  Element* tempstr = bs.m_string;
  int tempsize = bs.m_size;
  int tempcap = bs.m_capcity;

  bs.m_string = m_string;
  bs.m_size = m_size;
  bs.m_capcity = m_capcity;

  m_string = tempstr;
  m_size = tempsize;
  m_capcity = tempcap;
}

qb::base::BaseString::Element BaseString::at(int i) const {
  BASSERT(m_string && i >= 0 && i < m_size);
  return m_string[i];
}

BaseString::Element& BaseString::at(int i) {
  BASSERT(m_string && i >= 0 && i < m_size);
  return m_string[i];
}

////////////////////////////////////////////////////////////////////////////////
int BaseString::SearchString(const Element* mainStr, int mainStrLen,
                             const Element* subStr, int subStrLen, bool ic) {
  /*
  算法核心思想，从左向右匹配，遇到不匹配的看大串中匹配范围之外的右侧第一个字符在小串中的最右位置
  根据事先计算好的移动步长移动大串指针，直到匹配
  */
  if (mainStr == NULL || subStr == NULL) return npos;
  if (subStrLen > mainStrLen) return npos;

  int main_i = 0;
  int sub_j = 0;

  // 设定每个字符最右移动步长，保存每个字符的移动步长
  // 如果大串中匹配字符的右侧一个字符没在子串中，大串移动步长= 整个串的距离 +1
  // 如果大串中匹配范围内的右侧一个字符在子串中，大串移动距离= 子串长度 -
  // 这个字符在子串中的位置
  StackArray<int, 256> charStep;
  for (int i = 0; i < charStep.StackCapcity(); i++)
    charStep.GetBuf()[i] = subStrLen + 1;
  // 从左向右扫描一遍 保存子串中每个字符所需移动步长
  for (int i = 0; i < subStrLen; i++) {
    charStep.GetBuf()[(unsigned char)GetCaseChar(ic, subStr[i])] =
        subStrLen - i;
  }

  while (main_i < mainStrLen) {
    // 保存大串每次开始匹配的起始位置，便于移动指针
    int tem = main_i;
    while (sub_j < subStrLen) {
      if (GetCaseChar(ic, mainStr[main_i]) == GetCaseChar(ic, subStr[sub_j])) {
        main_i++;
        sub_j++;
        continue;
      } else {
        // 如果匹配范围外已经找不到右侧第一个字符，则匹配失败
        if (tem + subStrLen > mainStrLen) {
          return npos;
        }
        // 否则 移动步长 重新匹配
        char firstRightChar = GetCaseChar(ic, mainStr[tem + subStrLen]);
        main_i = tem + charStep[(unsigned char)firstRightChar];
        sub_j = 0;
        break;  // 退出本次失败匹配 重新一轮匹配
      }
    }
    if (sub_j == subStrLen) return main_i - subStrLen;
  }

  return npos;
}

// BaseString operator+(const BaseString& bs,const BaseString::Element* str)
//{
//	BaseString ret(bs);
//	return ret.operator +(str);
// }
// BaseString operator+(const BaseString& bs,const BaseString& plus)
//{
//	BaseString ret(bs);
//	return ret.append(plus);
// }
BaseString& operator+=(BaseString& bs, const BaseString::Element* str) {
  return bs.append(str);
}
BaseString& operator+=(BaseString& bs, const BaseString& plus) {
  return bs.append(plus);
}
bool operator<(const BaseString& left, const BaseString& right) {
  return left.compare(right.c_str(), right.size()) < 0;
}

/////////////////////////////////////////////////////////////////////////////////
KeyString::~KeyString() { destroy(); }

KeyString::KeyString(const char* str) : m_data(nullptr) { assign(str, -1); }

KeyString::KeyString(const char* str, int len) : m_data(nullptr) {
  assign(str, len);
}

KeyString::KeyString(const std::string& str) : m_data(nullptr) {
  assign(str.c_str(), str.size());
}

KeyString::KeyString(const ThisType& str) : m_data(nullptr) {
  assign(str.c_str(), str.size());
}

KeyString::KeyString(ThisType&& str) : m_data(str.m_data) {
  str.m_data = nullptr;
}

KeyString::KeyString() : m_data(nullptr) {}

qb::base::KeyString& KeyString::operator=(const KeyString& str) {
  assign(str.c_str(), str.size());
  return *this;
}

KeyString& KeyString::operator=(ThisType&& str) {
  std::swap(m_data, str.m_data);
  return *this;
}

KeyString& KeyString::operator=(const char* str) {
  assign(str, -1);
  return *this;
}

KeyString& KeyString::operator+=(const ThisType& str) {
  assign_plus(c_str(), size(), str.c_str(), str.size());
  return *this;
}

KeyString& KeyString::operator+=(const char* str) {
  assign_plus(c_str(), size(), str, -1);
  return *this;
}

const char* KeyString::c_str() const {
  static const char blank[4] = {0, 0, 0, 0};
  if (m_data == nullptr)
    return blank;
  else if (istiny()) {
    BASSERT(m_raw[3] == 0);
    return m_raw;
  }
  const char* ptr = pointer();
  return (((*ptr) & HighBit) ? (ptr + 2) : (ptr + 1));
}

int KeyString::size() const {
  if (m_data == nullptr)
    return 0;
  else if (istiny()) {
    BASSERT(m_raw[3] == 0);
    for (int i = 0; i < 3; i++) {
      if (m_raw[i] == '\0') return i;
    }
    return 3;
  }
  const char* ptr = pointer();
  if ((*ptr) & HighBit) {
    unsigned int hi = ((unsigned char)ptr[0]) & LowBitMask;
    unsigned int lo = (unsigned char)ptr[1];
    return (hi << 8) | lo;
  }
  return (unsigned char)ptr[0];
}

int KeyString::bytes() const {
  if (m_data == nullptr || istiny()) return 4;
  int len = size();
  return len >= TinyLength ? (sizeof(const char*) + len + 3)
                           : (sizeof(const char*) + len + 2);
}
bool KeyString::operator==(const char* str) const {
  int len = size();
  if (str) {
    int lens = strlen(str);
    if (lens == len) {
      return strncmp(c_str(), str, len) == 0;
    }
  }
  return len == 0;
}
bool KeyString::operator==(const ThisType& str) const {
  int len = size();
  if (len == str.size())
    return (len > 0) ? (strncmp(c_str(), str.c_str(), len) == 0) : true;
  return false;
}

bool KeyString::assign_plus(const char* str, int len, const char* post,
                            int postLen) {
  len = str ? (len <= 0 ? strlen(str) : len) : 0;
  postLen = post ? (postLen <= 0 ? strlen(post) : postLen) : 0;
  int total = len + postLen;
  if (total <= 0) {
    destroy();
    m_data = nullptr;
    return true;
  }
  if (total <= 3) {
    char raw[4] = {0, 0, 0, 0};
    if (len > 0) {
      memcpy(raw, str, len);
    }
    if (postLen > 0) {
      memcpy(raw + len, post, postLen);
    }
    raw[3] = 0;
    destroy();
    memcpy(m_raw, raw, 4);
    BASSERT(istiny());
    return true;
  }
  total = total >= MaxLength ? MaxLength : total;
  int extra = total >= TinyLength ? 2 : 1;
  char* data = new (std::nothrow) char[extra + total + 1];
  char* dest = data + extra;
  char* end = data + extra + total;
  if (len > 0) {
    memcpy(dest, str, len);
  }
  if (postLen > 0) {
    memcpy(dest + len, post, postLen);
  }
  *end = '\0';
  set_length(data, total);
  destroy();
  set_pointer(data);
  return true;
}

bool KeyString::assign(const char* str, int len) {
  if (len < 0) len = str ? strlen(str) : 0;
  if (len <= 0) {
    destroy();
    m_data = nullptr;
    return true;
  } else if (len <= 3) {
    char raw[4] = {0, 0, 0, 0};
    memcpy(raw, str, len);
    raw[3] = 0;
    destroy();
    memcpy(m_raw, raw, 4);
    BASSERT(istiny());
    return true;
  }
  len = len >= MaxLength ? MaxLength : len;
  int extra = len >= TinyLength ? 2 : 1;
  char* data = new (std::nothrow) char[extra + len + 1];
  if (data) {
    memcpy(data + extra, str, len);
    data[extra + len] = 0;
    set_length(data, len);
    destroy();
    set_pointer(data);
    return true;
  }
  return false;
}

void KeyString::destroy() {
  if (!istiny() && m_data) delete[] pointer();
  m_data = nullptr;
}

bool KeyString::haspointer() const { return (uintptr_t)m_data & MostBitFlag; }

}  // namespace base
}  // namespace qb